#include "StdAfx.h"
#include "NetworkController.h"

/// EXPLODE /////

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> splitStr(const std::string &s, char delim = '#')
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}


///////////////////// PACKET STREAM //////////////////////////////

sf::Packet& operator <<(sf::Packet& Packet, const HPacket& h)
{
	return Packet << h.m_cmd_number << h.m_infos_cmd << h.m_time;
}

sf::Packet& operator >>(sf::Packet& Packet, HPacket& h)
{
	 return Packet >> h.m_cmd_number >> h.m_infos_cmd >> h.m_time;
}

///////////////////// LOOP //////////////////////////////////

static void networkLoop()
{
	PlayerNetwork cu = DataBase::getInstance()->getCurrentPlayer();

	while (NetworkController::getInstance()->getStatus())
	{
		sf::Packet packet;
		sf::Socket::Status st;
		HPacket hp;
		PlayerNetwork cu = DataBase::getInstance()->getCurrentPlayer();


		//RECIEVE LOGIC
		st = NetworkController::getInstance()->m_socket.receive(packet);
			
		switch(st)
		{
		case sf::Socket::Status::Done:
			if (packet)
			{
				packet >> hp;
			
				switch(hp.m_cmd_number)
				{
				case 0: NetworkController::getInstance()->startGame(hp.m_infos_cmd.toAnsiString());
						break;
				case 1: NetworkController::getInstance()->refreshTime(hp.m_infos_cmd.toAnsiString());
						break;
				case 2: NetworkController::getInstance()->endGame(hp.m_infos_cmd.toAnsiString());
						break;
				case 4: NetworkController::getInstance()->refreshPlayers(hp.m_infos_cmd.toAnsiString());
						break;
				case 5: NetworkController::getInstance()->deadPlayer(hp.m_infos_cmd.toAnsiString());
						break;
				case 6: NetworkController::getInstance()->youAreDead(hp.m_infos_cmd.toAnsiString());
						break;
				}
			}
			break;
		case sf::Socket::Status::Disconnected:
			//NetworkController::getInstance()->setStatus(false);
			break;
		}

		if (cu.m_posX != DataBase::getInstance()->getCurrentPlayer().m_posX ||
			cu.m_posY != DataBase::getInstance()->getCurrentPlayer().m_posY)
		{
			std::ostringstream oss1, oss2, oss3;
			cu = DataBase::getInstance()->getCurrentPlayer();

			oss1.str("");
			oss2.str("");
			oss3.str("");

			oss1 << cu.m_posX;
			oss2 << cu.m_posY;
			oss3 << DataBase::getInstance()->getNumberPlayer();


			hp.m_cmd_number = 3;
			hp.m_infos_cmd = sf::String(oss1.str() + "#" + oss2.str() + "#" + oss3.str());
			hp.m_time = sf::String("0");

			//std::cout << "SEND PACKET " << hp.m_infos_cmd.toAnsiString() << std::endl;

			packet << hp;

			st = NetworkController::getInstance()->m_socket.send(packet);
		}
	}
}

NetworkController::NetworkController(void)
{
}

NetworkController::~NetworkController(void)
{
}

bool NetworkController::startService(std::string ip, int port)
{
	DataBase::getInstance()->initDatabase();
	if ((connectSocket(ip, port)) == false)
		return false;
	
	std::cout << "CONNECTED" << std::endl;
	m_networkLoop.create(networkLoop, NULL);
	return true;
}

void NetworkController::stopService()
{
	setStatus(false);
	m_networkLoop.join();
}

bool	NetworkController::connectSocket(std::string ip, int port)
{
	sf::Socket::Status st;
	setStatus(false);

	m_socket.setBlocking(false);
	st = m_socket.connect(ip, port); 

	if (st == sf::Socket::Status::Error)
		return false;

	setStatus(true);
	return true;
}


void	NetworkController::setStatus(bool s)
{
	m_mutexStatus.lock();
	m_status = s;
	m_mutexStatus.unlock();
}

bool	NetworkController::getStatus()
{
	m_mutexStatus.lock();
	bool s = m_status;
	m_mutexStatus.unlock();
	return s;
}

void NetworkController::startGame(std::string info)
{
	PlayerNetwork cu;
	
	std::cout << "INFO " << info << std::endl;

	std::vector<std::string> temp = splitStr(info, '/');

	cu.m_number = DataBase::getInstance()->getNumberPlayer();
	cu.m_type = (TypePlayer)atoi(temp[1].c_str());

	std::cout << "Player ID number: " << cu.m_number << std::endl;

	DataBase::getInstance()->setCurrentPlayer(cu);

	DataBase::getInstance()->setState(GameState::START);
	DataBase::getInstance()->setState(GameState::INGAME);
}

void NetworkController::refreshTime(std::string info)
{
	//
}

void NetworkController::endGame(std::string info)
{
	DataBase::getInstance()->setState(GameState::STOP);
}

void NetworkController::refreshPlayers(std::string info)
{
	//return;
	PlayerNetwork mo;
	
	std::vector<std::string> tabtemp = splitStr(info, '/');

	//std::cout << "Players number=" <<  tabtemp.size() << std::endl;
	for (int it = 0; it < tabtemp.size(); it++)
	{
		std::vector<std::string> tabtemptemp =  splitStr(tabtemp[it], '#');
		
		mo.m_posX = atoi(tabtemptemp[0].c_str());
		mo.m_posY = atoi(tabtemptemp[1].c_str());
		mo.m_number = atoi(tabtemptemp[2].c_str());

		//std::cout << "x=" << mo.m_posX << "y=" << mo.m_posY << "number=" << mo.m_number << std::endl;

		if (mo.m_number != DataBase::getInstance()->getNumberPlayer())
			DataBase::getInstance()->modifyPlayer(mo);
	}
}

void NetworkController::deadPlayer(std::string info)
{
	DataBase::getInstance()->erasePlayerNumber(atoi(info.c_str()));
}

void NetworkController::youAreDead(std::string info)
{
	std::cout << "YOU ARE DEAD" << std::endl;
}